package com.dragon.common.spring.openapi.customizers.openapi;

import com.dragon.common.spring.openapi.SchemaHelper;
import com.dragon.common.spring.openapi.httppack.OpenApiConstants;
import com.google.gson.Gson;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.Schema;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Order(-200)
@Component
public class ValueResultOpenApiCustomizer implements OpenApiCustomizer {
    private static final Logger log = LoggerFactory.getLogger(ValueResultOpenApiCustomizer.class);

    @Autowired
    private Gson gson;

    @Override
    public void customise(OpenAPI openApi) {
        log.info("ValueResultOpenApiCustomizer~~");
        // 确保HttpResult Schema存在
        ensureHttpResultSchemaExists(openApi);

        // 遍历所有路径
        openApi.getPaths().forEach((path, pathItem) -> {
            // 处理所有HTTP方法
            pathItem.readOperationsMap().forEach((httpMethod, operation) -> {
                // 检查是否需要跳过包装（方法返回类型已经是ValueResult）
                if (shouldSkipWrapValueResult(operation)) {
                    return;
                }
                // 3. 读取扩展标记决定是否包装
                if (!shouldWrapValueResult(operation)) {
                    return;
                }

                // 包装响应
                wrapOperationResponsesWithValueResult(openApi, operation);
            });
        });
    }

    /**
     * 检查是否需要包装ValueResult
     *
     * @param operation
     * @return
     */
    private boolean shouldWrapValueResult(Operation operation) {
        Object flag = operation.getExtensions().get(OpenApiConstants.X_WRAP_WITH_VALUE_RESULT);
        return flag instanceof Boolean ? (Boolean) flag : false;
    }

    /**
     * 确保ValueResult Schema存在
     *
     * @param openApi
     */
    private void ensureHttpResultSchemaExists(OpenAPI openApi) {
        Components components = openApi.getComponents();
        if (components == null) {
            openApi.setComponents(new Components());
        }

        if (components != null) {
            SchemaHelper.addValueResultSchema(components);
        }
    }

    /**
     * 检查是否需要跳过包装
     *
     * @param operation
     * @return
     */
    private boolean shouldSkipWrapValueResult(Operation operation) {
        // 如果有自定义扩展属性标记已经包装过，则跳过
        if (operation.getExtensions() != null &&
                operation.getExtensions().containsKey(OpenApiConstants.X_VALUE_RESULT_ALREADY_WRAPPED)) {
            return true;
        }

        // 检查响应结构是否已经是HttpResult格式
        return operation.getResponses().values().stream()
                .flatMap(response -> response.getContent().values().stream())
                .anyMatch(content -> {
                    Schema<?> schema = content.getSchema();
                    return schema != null && schema.get$ref() != null &&
                            schema.get$ref().contains("HttpResult");
                });
    }

    /**
     * 包裹ValueResult
     *
     * @param openApi
     * @param operation
     */
    private void wrapOperationResponsesWithValueResult(OpenAPI openApi, Operation operation) {
        operation.getResponses().forEach((statusCode, response) -> {
            if (response.getContent() != null) {
                response.getContent().forEach((mediaType, content) -> {
                    Schema<?> originalSchema = content.getSchema();

                    // 跳过空Schema
                    if (originalSchema == null) {
                        return;
                    }

                    // 更新valueResult的data属性
                    updateValueResultDataSchema(openApi, originalSchema);
                });
            }
        });

        // 标记已经处理过
        operation.addExtension(OpenApiConstants.X_VALUE_RESULT_ALREADY_WRAPPED, true);
    }

    /**
     * 包裹ValueResult
     *
     * @param openApi
     * @param originalSchema
     * @return
     */
    private void updateValueResultDataSchema(OpenAPI openApi, Schema<?> originalSchema) {
        // 原有的Schema名称
        String ref = originalSchema.get$ref();
        // 如果不为空，就是引用类型，不处理
        if (ref != null) {
            return;
        }
        // 包裹ValueResult
        String type = originalSchema.getType();
        String originalSchemaName = convertSchemaName(type);

        // 新的Schema名称
        String newSchemaName = "ValueResult" + originalSchemaName;
        // 检查是否已存在，不存在要创建
        Components components = openApi.getComponents();
        Schema<?> valueResultSchema;
        if (components.getSchemas().containsKey(newSchemaName)) {
            valueResultSchema = components.getSchemas().get(newSchemaName);
        } else {
            valueResultSchema = SchemaHelper.createValueResultExtSchema(newSchemaName, type);

            // 在Schema列表中添加新生成的Schema
            components.addSchemas(newSchemaName, valueResultSchema);
        }

        // 重新指向
        originalSchema.set$ref("#/components/schemas/" + newSchemaName);
    }

    /**
     * 转换Schema名称
     *
     * @param type
     * @return
     */
    private String convertSchemaName(String type) {
        if (StringUtils.isEmpty(type)) {
            return "";
        }
        // 首字母大写
        return StringUtils.capitalize(type);
    }

}